package org.totoro.openstreet.thread;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.totoro.openstreet.bo.*;

import java.io.IOException;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author daocr
 * @date 2019/9/27
 */
public class ConcurrentAnalysisNode {

    private ExecutorService subAreaPool;

    public ConcurrentAnalysisNode(ExecutorService subAreaPool) {
        this.subAreaPool = subAreaPool;
    }

    /***
     * 获取节 经纬度数据
     * @param element
     */
    public PointNode getNode(Element element, Integer sort) {

        String id = element.attr("id");
        String timestamp = element.attr("timestamp");
        String lat = element.attr("lat");
        String lng = element.attr("lon");

        return new PointNode(id, timestamp, lat, lng, sort);
    }


    /**
     * 外部 轮廓 一小段线
     *
     * @param element
     * @return
     * @throws IOException
     */
    public void getWay(Element element) throws IOException {

        SubArea subArea = new SubArea();


        // 内部 区域
        Elements subarea = element.getElementsByAttributeValue("role", "subarea");

        if (subarea != null && subarea.size() > 0 && subarea.first() != element) {

            subarea.stream().forEach(item -> {
                // 添加到线程池
                subAreaPool.submit(new SpiderThread(element, item, subAreaPool));
            });
        }


        Elements adminLevel = element.getElementsByAttributeValue("k", "admin_level");

        if (adminLevel != null && adminLevel.size() > 0) {
            subArea.setLevel(Level.of(Integer.valueOf(adminLevel.first().attr("v"))));
        }

        Elements nameElement = element.getElementsByAttributeValue("k", "name");

        if (nameElement != null && nameElement.size() > 0) {
            subArea.setName(nameElement.first().attr("v"));
        }

        // 行政中心
        Elements adminCentre = element.getElementsByAttributeValue("role", "admin_centre");

        if (adminCentre != null && adminCentre.size() > 0) {

            AdminCentreNode adminCentrePointNode = getAdminCentrePointNode(adminCentre.first());
            subArea.setAdminCentre(adminCentrePointNode);

            System.out.println(adminCentrePointNode);
        }

        // 轮廓线
        Elements outer = element.getElementsByAttributeValue("role", "outer");

        if (outer != null && outer.size() > 0) {
            List<OuterLine> collect = getOuterLines(outer);
            subArea.setOuterLines(collect);
        }


        // 排除 轮廓线
        Elements inner = element.getElementsByAttributeValue("role", "inner");

        if (inner != null && inner.size() > 0) {
            List<OuterLine> collect = getOuterLines(inner);
            subArea.setExcludeOutlines(collect);
        }

    }

    private List<OuterLine> getOuterLines(Elements outer) {
        return outer.stream().map(element1 -> {
            try {
                return getOuterLine(element1);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }).filter(e -> e != null).collect(Collectors.toList());
    }

    /**
     * 获取轮廓线
     *
     * @param element
     * @return
     */
    public OuterLine getOuterLine(Element element) throws IOException {

        OuterLine outerLine = new OuterLine();

        String ref = element.attr("ref");

        Document document = Jsoup.connect("https://www.openstreetmap.org/api/0.6/way/" + ref).get();

        Element way = document.getElementsByTag("way").first();

        String id = way.attr("id");
        String timestamp = way.attr("timestamp");

        Elements nameElements = element.getElementsByAttributeValue("k", "name");

        outerLine.setId(id);
        outerLine.setTimestamp(timestamp);

        if (nameElements != null && nameElements.size() > 0) {
            outerLine.setName(nameElements.first().attr("v"));
        }

        //获取 经纬度
        Elements pointElement = document.getElementsByTag("nd");

        if (pointElement != null && pointElement.size() > 0) {

            // 添加 排序
            AtomicReference<Integer> sort = new AtomicReference<>(0);
            List<PointNode> collect = pointElement.stream().map(e -> {
                try {
                    return this.getPointNode(e, sort.getAndSet(sort.get() + 1));
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
                return null;
            }).filter(Objects::nonNull).collect(Collectors.toList());

            outerLine.setPointNodes(collect);
        }

        System.out.println(outerLine);

        return outerLine;

    }

    /**
     * 轮廓线构成的点
     *
     * @param element
     * @return
     * @throws IOException
     */
    public PointNode getPointNode(Element element, Integer sort) throws IOException {


        String id = element.attr("ref");

        Document document = Jsoup.connect("https://www.openstreetmap.org/api/0.6/node/" + id).get();

        Elements nodeElement = document.getElementsByTag("node");

        if (nodeElement != null && nodeElement.size() > 0) {

            Element first = nodeElement.first();

            PointNode node = this.getNode(first, sort);

//            System.out.println("thrad Id: " + Thread.currentThread().getId() + node);

            return node;
        }


        return null;

    }

    /**
     * 获取行政中心节点
     *
     * @param element
     * @return
     * @throws IOException
     */
    public AdminCentreNode getAdminCentrePointNode(Element element) throws IOException {


        AdminCentreNode adminCentreNode = new AdminCentreNode();

        String ref = element.attr("ref");

        Document document = Jsoup.connect("https://www.openstreetmap.org/api/0.6/node/" + ref).get();
        Element node = document.getElementsByTag("node").first();
        Element nameElement = document.getElementsByAttributeValue("k", "name").first();

        adminCentreNode.setId(node.attr("id"));
        adminCentreNode.setTimestamp(node.attr("timestamp"));
        adminCentreNode.setLat(node.attr("lat"));
        adminCentreNode.setLng(node.attr("lon"));
        adminCentreNode.setName(nameElement.attr("v"));

        Elements oldNames = document.getElementsByAttributeValueMatching("k", "^old_name\\d*");

        if (oldNames != null && oldNames.size() > 0) {
            List<String> v = oldNames.stream().map(e -> e.attr("v"))
                    .collect(Collectors.toList());
            adminCentreNode.setOldName(v);
        }


        return adminCentreNode;
    }
}
